package com.xbongbong.pro.statistics.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.domain.entity.ext.CkPaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.StatisticBiFormDataEntity;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.thread.TransmittableThreadLocalUtil;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.MD5Util;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.pro.bi.commons.pojo.AggFieldPojo;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.errorcodes.BiErrorCodeEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.DrillFieldEnum;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.help.CustomHelp;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.result.pojo.AggsBucketsPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.DiyResultDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartAnalysisVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.pro.statistics.factory.ChartTypeAnalysisFactory;
import com.xbongbong.pro.statistics.help.CkResultHelp;
import com.xbongbong.pro.statistics.help.CommonHelper;
import com.xbongbong.pro.statistics.help.QueryTableSumHelper;
import com.xbongbong.pro.statistics.help.StatisticsTableHelper;
import com.xbongbong.pro.statistics.pojo.dto.ChartAnalysisDTO;
import com.xbongbong.pro.statistics.pojo.dto.GenerateSqlDTO;
import com.xbongbong.pro.statistics.pojo.vo.GenerateSqlVO;
import com.xbongbong.pro.statistics.service.CkPaasFormDataService;
import com.xbongbong.pro.statistics.service.CkResultService;
import com.xbongbong.pro.statistics.service.StatisticBiFormDataService;
import com.xbongbong.pro.statistics.strategy.chart.type.ChartTypeStrategyService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author  l
 */
@Service("ckResultService")
public class CkResultServiceImpl implements CkResultService {
    @Resource
    private StatisticBiFormDataService statisticBiFormDataService;
    @Resource
    private CkPaasFormDataService ckPaasFormDataService;
    @Resource
    private CustomHelp customHelp;
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private QueryTableSumHelper queryTableSumHelper;
    @Resource
    private CkResultHelp ckResultHelp;
    @Resource
    private CommonHelper commonHelper;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private StatisticsTableHelper statisticsTableHelper;

    public Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public ChartResultDetailVO gitDiyResult(DiyResultDTO diyResultDTO) throws XbbException {
        ChartResultDetailVO chartResultDetailVO = diyResultDTO.getChartResultDetailVO();
        try {
            ChartEntity chartEntity = diyResultDTO.getChartEntity();
            chartResultDetailVO.setChartEntity(chartEntity);
            SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(chartEntity.getDriverSources(), SlaveSourcePojo.class);
            TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverSourcePojo.getBusinessType(), driverSourcePojo.getMenuId(), null);
            JSONArray tableHead = new JSONArray();
            Map<JSONObject, FieldAttrPojo> parseAttrMap = new HashMap<>(XbbConstant.INITIALCAPACITY);
            Integer chartType = chartEntity.getChartType();
            ChartTypeStrategyService chartTypeStrategyService = ChartTypeAnalysisFactory.getChartTypeStrategyService(chartType);
            ChartResultPojo chartResultPojo = diyResultDTO.getChartResultPojo();
            boolean isSingle;
            if (chartEntity.getSingle() == null) {
                isSingle = true; 
            } else {
                isSingle = EsUtil.getSingle(chartEntity);
            }
            // 处理不显示离职人员
            chartResultHelp.handleLeaveNoShow(chartEntity);
            // 是否是预警脚本跑的
            Boolean isWarningSync = chartResultPojo.getIsWarningSync();
            if (Objects.isNull(isWarningSync) || !isWarningSync){
                //表单权限
                customHelp.setPermission(chartEntity,diyResultDTO);
            }
            GenerateSqlDTO generateSqlDTO = new GenerateSqlDTO();
            generateSqlDTO.setChartEntity(chartEntity);
            generateSqlDTO.setChartResultPojo(chartResultPojo);
            generateSqlDTO.setTableHead(tableHead);
            generateSqlDTO.setSingle(isSingle);
            generateSqlDTO.setParseAttrMap(parseAttrMap);
            //多表对关联表的特殊处理
            commonHelper.biProductFliter(chartEntity, isSingle);
            //sql的生成
            GenerateSqlVO generateSqlVO = null;
            try {
                generateSqlVO = chartTypeStrategyService.generateSql(generateSqlDTO);
            } catch (XbbException e) {
                throw e;
            }catch (Exception e) {
                logger.error("chartId==="+chartEntity.getId(),e);
                throw new XbbException(BiErrorCodeEnum.API_ERROR_241023);
            }
            StringBuffer stringBufferSql = generateSqlVO.getStringBufferSql();
            if(stringBufferSql == null || stringBufferSql.length() <= 0){
                chartResultDetailVO.setChart(new ArrayList<>());
                return chartResultDetailVO;
            }
            String sql = stringBufferSql.toString();
            PageHelper pageHelper = generateSqlVO.getPageHelper();
            Map<String, AggFieldPojo> aggFieldMap = generateSqlVO.getAggFieldMap();
            List<CkPaasFormDataEntityExt> ckSingleResultList = null;
            List<StatisticBiFormDataEntity> ckMultiResultList = null;
            if(commonHelper.getPrintLog(diyResultDTO.getCorpid())){
                //操作人   图表id
                logger.info("CK===chartId==="+chartEntity.getId()+"===SQL==="+sql);
            }

            //统计表
            boolean statisticsTable = Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode()) ;
            // 加入这步处理是因为钻取之后翻页的时候重新划分行列分组时使用的原来的图表，所有需要先处理图表结构
            if (statisticsTable) {
                // 钻取之后需要改变左侧列分组数据，目的是插入钻取的属性值(列分组)
                statisticsTableHelper.dealTableRowOrColAttrDrillSign(DrillFieldEnum.COL_GROUP_ATTR.getAlias(), chartEntity.getColGroupAttr(), diyResultDTO, chartEntity);
                // 钻取之后需要改变左侧行分组数据，目的是插入钻取的属性值(行分组)
                statisticsTableHelper.dealTableRowOrColAttrDrillSign(DrillFieldEnum.ROW_GROUP_ATTR.getAlias(), chartEntity.getRowGroupAttr(), diyResultDTO, chartEntity);
            }
            String redisKey = null;
            if(statisticsTable){
                redisKey =  MD5Util.EncoderByMd5(sql);
            }
            //统计表翻页取缓存
            if(statisticsTable && Objects.equals(chartResultPojo.getPageTurn(),1)) {
                String responseStr = paasRedisHelper.getValue(RedisPrefixConstant.STATISTICS_TABLE_CK_RESULT, redisKey);
                if(StringUtil.isNotEmpty(responseStr)){
                    statisticsTableHelper.statisticTableResult(chartResultDetailVO, chartEntity, chartResultPojo,  pageHelper, responseStr);
                }else {
                    dealDiyResult(diyResultDTO, chartResultDetailVO, chartEntity, tableHead, parseAttrMap, chartTypeStrategyService, chartResultPojo, isSingle, generateSqlVO, sql, pageHelper, aggFieldMap, statisticsTable, redisKey);
                }
            }else {
                dealDiyResult(diyResultDTO, chartResultDetailVO, chartEntity, tableHead, parseAttrMap, chartTypeStrategyService, chartResultPojo, isSingle, generateSqlVO, sql, pageHelper, aggFieldMap, statisticsTable, redisKey);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e){
            logger.error("chartId---==="+ diyResultDTO.getChartEntity().getId(),e);
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241023);
        }
        return chartResultDetailVO;
    }


    private void dealDiyResult(DiyResultDTO diyResultDTO, ChartResultDetailVO chartResultDetailVO, ChartEntity chartEntity, JSONArray tableHead, Map<JSONObject, FieldAttrPojo> parseAttrMap, ChartTypeStrategyService chartTypeStrategyService, ChartResultPojo chartResultPojo, boolean isSingle, GenerateSqlVO generateSqlVO, String sql, PageHelper pageHelper, Map<String, AggFieldPojo> aggFieldMap, boolean statisticsTable, String redisKey) throws XbbException {
        List<CkPaasFormDataEntityExt> ckSingleResultList;
        List ckMultiResultList;
        //数据
        JSONArray jsonArray = new JSONArray();
        try {
            if (isSingle) {
                ckSingleResultList = ckPaasFormDataService.findEntitysBySql(sql);
                if(CollectionsUtil.isNotEmpty(ckSingleResultList)){
                    jsonArray = JSONArray.parseArray(JSON.toJSONString(ckSingleResultList));
                }
            } else {
                ckMultiResultList = statisticBiFormDataService.findEntitys(sql);
                if(CollectionsUtil.isNotEmpty(ckMultiResultList)){
                    jsonArray = JSONArray.parseArray(JSON.toJSONString(ckMultiResultList));
                }
            }
        } catch (Exception e) {
            logger.error("chartId==="+ chartEntity.getId(),e);
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241023);
        }
        //根据图表类型渲染结果
        ChartAnalysisDTO chartAnalysisDTO = new ChartAnalysisDTO();
        BeanUtil.copyProperties(diyResultDTO, chartAnalysisDTO, true);
        chartAnalysisDTO.setResultArray(jsonArray);
        chartAnalysisDTO.setPageHelper(pageHelper);
        chartAnalysisDTO.setTableHead(tableHead);
        chartAnalysisDTO.setParseAttrMap(parseAttrMap);
        chartAnalysisDTO.setSummaryAttrMap(generateSqlVO.getSummaryAttrMap());
        chartAnalysisDTO.setSecondTargetKey(generateSqlVO.getSecondTargetKey());
        chartAnalysisDTO.setAggFieldMap(aggFieldMap);
        chartAnalysisDTO.setSingleFlag(isSingle);
        chartAnalysisDTO.setPageTurn(chartResultPojo.getPageTurn());
        //todo 这里做区分， 总计、小计、总计小计
        chooseStatisticsTableTotal(statisticsTable,isSingle,chartEntity,chartAnalysisDTO,generateSqlVO);
        // 渲染
        ChartAnalysisVO chartAnalysisVO = chartTypeStrategyService.chartAnalysis(chartAnalysisDTO);
        JSONObject result = Objects.nonNull(chartAnalysisVO) ? chartAnalysisVO.getResult() : new JSONObject();
        //自定义图表，只返回图的信息即可
        if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_QUERY_TABLE.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.TARGET_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.SECOND_TARGET_CHART.getCode())
        ) {
            ResultTableVO resultTableVO = new ResultTableVO();
            if (result != null && result.size() > 0) {
                if(statisticsTable){
                    resultTableVO = statisticsTableHelper.statisticsTableConstruction(chartEntity, chartResultPojo, pageHelper, redisKey, result, resultTableVO);
                }else {
                    resultTableVO = JSON.parseObject(result.toJSONString(), ResultTableVO.class);
                }
            }
            resultTableVO.setPageHelper(pageHelper);
            resultTableVO.setTableName(chartEntity.getName());
            resultTableVO.setChartType(chartEntity.getChartType());

            // 返回钻取的层级信息
            statisticsTableHelper.dealTableDrillInfo(chartEntity, chartResultPojo, resultTableVO);

            chartResultDetailVO.setTable(resultTableVO);
            if(Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_QUERY_TABLE.getCode())){
                if (chartEntity.getSummaryAttr() != null && chartEntity.getSummaryAttr().size() > 0) {
                    boolean penetrateFlag = ckResultHelp.getPenetrateFlag(chartEntity.getFilter());
                    //第一页且非穿透
                    if(Objects.equals(chartResultPojo.getPage(),1) && !penetrateFlag){
                        List<AggsBucketsPojo> aggList = queryTableSumHelper.queryTableSum(chartEntity, sql, isSingle);
                        chartResultDetailVO.setAggList(aggList);
                    }
                }
            }
        } else if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.BAR_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.BROADWISE_BAR_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.LINE_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.AREA_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.RADAR_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PIE_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.BIAXIAL_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.MAP_CUSTOM.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.SCATTER_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.FUNNEL.getCode())) {
            ResultChartVO resultChartVO = new ResultChartVO();
            if (result != null && result.size() > 0) {
                resultChartVO = JSON.parseObject(result.toJSONString(), ResultChartVO.class);
            }
            List<ResultChartVO> chartVOList = new ArrayList<>();
            chartVOList.add(resultChartVO);
            chartResultDetailVO.setChart(chartVOList);
        }
    }

    /**
     * 统计表 - 获取总计 || 小计 ||总计小计的值
     *
     * @param statisticsTable  是否统计表 true-是  false-否
     * @param isSingle  是否单数据源  true-是  false-否
     * @param chartEntity   图表实体
     * @param chartAnalysisDTO 请求实体
     * @param generateSqlVO sql拼接实体
     * @author zyy
     * @date 2022/7/28
     * @version v1.0
     */
    private void chooseStatisticsTableTotal(boolean statisticsTable, boolean isSingle, ChartEntity chartEntity, ChartAnalysisDTO chartAnalysisDTO, GenerateSqlVO generateSqlVO) throws XbbException {
        if(!statisticsTable){
            return;
        }
        try {
            switch (chartEntity.getSum()) {
                case 0:
                    //小计值
                    getSubTotalResult(chartAnalysisDTO,isSingle,generateSqlVO);
                    break;
                case 1:
                    //总计值
                    getSumAndSumRightTotalResult(chartAnalysisDTO,isSingle,generateSqlVO);
                    break;
                case 2:
                    // 总计 & 小计
                    getSubTotalResult(chartAnalysisDTO,isSingle,generateSqlVO);
                    getSumAndSumRightTotalResult(chartAnalysisDTO,isSingle,generateSqlVO);
                    break;
            }
        }catch(Exception e){
            logger.error("chartId==sum=" + chartEntity.getId(), e);
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241023);
        }
    }

    /**
     * 统计表 - 获取 下方总计、右侧总计
     *
     * @param chartAnalysisDTO  入参实体
     * @param isSingle          是否单表
     * @param generateSqlVO     结果响应实体
     * @author zyy
     * @date 2022/8/22
     * @version v1.0
     */
    private void getSumAndSumRightTotalResult(ChartAnalysisDTO chartAnalysisDTO, boolean isSingle, GenerateSqlVO generateSqlVO) {
        if (isSingle) {
            //下方总计
            chartAnalysisDTO.setSumJsonArray(JSONArray.parseArray(JSON.toJSONString(ckPaasFormDataService.findEntitysBySql(generateSqlVO.getSumTotalSql()))));
            //右侧总计
            chartAnalysisDTO.setSumRightJsonArray(JSONArray.parseArray(JSON.toJSONString(ckPaasFormDataService.findEntitysBySql(generateSqlVO.getSumRightTotalSql()))));
            //总计的总计
            if(StringUtil.isNotEmpty(generateSqlVO.getTotalOfTotalSql())){
                chartAnalysisDTO.setTotalOfTotalJsonArray(JSONArray.parseArray(JSON.toJSONString(ckPaasFormDataService.findEntitysBySql(generateSqlVO.getTotalOfTotalSql()))));
            }
        } else {
            chartAnalysisDTO.setSumJsonArray(JSONArray.parseArray(JSON.toJSONString(statisticBiFormDataService.findEntitys(generateSqlVO.getSumTotalSql()))));
            chartAnalysisDTO.setSumRightJsonArray(JSONArray.parseArray(JSON.toJSONString(statisticBiFormDataService.findEntitys(generateSqlVO.getSumRightTotalSql()))));
            //总计的总计
            if(StringUtil.isNotEmpty(generateSqlVO.getTotalOfTotalSql())){
                chartAnalysisDTO.setTotalOfTotalJsonArray(JSONArray.parseArray(JSON.toJSONString(statisticBiFormDataService.findEntitys(generateSqlVO.getTotalOfTotalSql()))));
            }
        }
    }

    /**
     * 统计表 - 获取小计值
     *
     * @param chartAnalysisDTO  入参实体
     * @param isSingle          是否单表
     * @param generateSqlVO     结果响应实体
     * @author zyy
     * @date 2022/8/22
     * @version v1.0
     */
    private void getSubTotalResult(ChartAnalysisDTO chartAnalysisDTO, boolean isSingle, GenerateSqlVO generateSqlVO) {
        //小计并且只设置了列分组时，不发起调用，直接在结果中以源数据作为小计值
        if(StringUtils.isNotBlank(generateSqlVO.getSubTotalSql())){
            if (isSingle) {
                chartAnalysisDTO.setSubTotalJsonArray(JSONArray.parseArray(JSONObject.toJSONString(ckPaasFormDataService.findEntitysBySql(generateSqlVO.getSubTotalSql()))));
            }else{
                chartAnalysisDTO.setSubTotalJsonArray(JSONArray.parseArray(JSONObject.toJSONString(statisticBiFormDataService.findEntitys(generateSqlVO.getSubTotalSql()))));
            }
        }
    }


    @Override
    public ChartAnalysisVO connTest(BaseDTO baseDTO) throws XbbException {
        ChartAnalysisVO vo = new ChartAnalysisVO();
        List<CkPaasFormDataEntityExt> ckSingleResultList = ckPaasFormDataService.findEntitysBySql("SELECT id from tb_saas_customer LIMIT 1");
        logger.info(ckSingleResultList.size()+"========"+ckSingleResultList.get(0).getId());
        JSONObject id = new JSONObject();
        id.put("id", ckSingleResultList.get(0).getId());
        vo.setResult( id);
        return vo;
    }


}
